package com.kavadani.profiles;

import java.util.Iterator;
import java.util.Set;

import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.RemoteException;
import android.widget.Toast;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import com.kavadani.remoteservice.IRemoteService;
import com.kavadani.remoteservice.IRemoteServiceCallback;


abstract public class RemoteServiceClientActivity extends Activity {
	
	protected int remoteConnectionStatus = -1;
	
	private IRemoteService mService;
	private boolean mIsBound = false;
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		// --	
		if(mIsBound == false) {
			mIsBound = bindService(new Intent(IRemoteService.class.getName()), 
					mConnection, Context.BIND_AUTO_CREATE);
        }
		// --
	}
	
	
	
	@Override
	public void onDestroy() {
		
		if(this.mService != null) {
			try {
				mService.unregisterCallback(mCallback);
			} 
			catch (RemoteException e) {
				//e.printStackTrace();
			}
			
			if(mIsBound) {
				unbindService(mConnection);
				mIsBound = false;
			}
		}
		
		super.onDestroy();
	}
	
	
	
	
	// --- Remote Service Communication --------------------------------------
	
	protected void onServiceConnectionStatus(boolean connected) {
		
		if(connected) { 
			// textView1.setText("Service connected, register profile.");
			Toast.makeText(RemoteServiceClientActivity.this, 
					"Service connected.", Toast.LENGTH_SHORT).show();
		}
		else {
			Toast.makeText(RemoteServiceClientActivity.this, 
					"Service diconnected.", Toast.LENGTH_SHORT).show();
		}
	}
	
	
	protected void onRemoteConnectionStatus() {
		this.setTitle("Connection Status: " + this.remoteConnectionStatus);
	}
	
	protected void onRequestFailed(Bundle bundle) {
		
	}
	
	protected void onReceive(JSONArray jarr) {
		
	}
	
	protected void onReceive(JSONObject json) {
		
	}
	
	protected void onRequestResult(JSONArray jarr) {
		
	}
	
	protected void onRequestResult(JSONObject json) {
		
	}
	
	
	private void onMessageReceived(Bundle bundle) {
		int what = 0;
		if(bundle.containsKey("what")) { // system messages
			what = bundle.getInt("what");
		}
		// --
		switch(what) {
		case 1: // Remote Connection status
			this.remoteConnectionStatus = bundle.getInt("status");
			// getApp().setRemoteConnectionStatus(status);
			onRemoteConnectionStatus();
			break;
		case 2:  // request failed
			onRequestFailed(bundle);
			break;
		case 3: { // result
			if(bundle.containsKey("data")) {
				String data = bundle.getString("data");
				try {
					JSONObject json = new JSONObject(data);
					if (!json.has("action") && bundle.containsKey("action")) {
						json.put("action", bundle.get("action"));
					}
					onRequestResult(json);
				}
				catch (JSONException e) {
					try {
						onRequestResult(new JSONArray(data));
					}
					catch (JSONException e2) {
						e.printStackTrace();
						return; // error
					}
				}
			}
			else {
				JSONObject json = toJSON(bundle);
				if(json == null) { return; } 		// TODO:
				onReceive(json);
			}
			}
			break;
		default: {
			if(bundle.containsKey("data")) {
				String data = bundle.getString("data");
				try { onReceive(new JSONObject(data)); }
				catch (JSONException e) {
					try { onReceive(new JSONArray(data)); }
					catch (JSONException e2) {
						e.printStackTrace();
						return; // error
					}
				}
			}
			else {
				JSONObject json = toJSON(bundle);
				if(json == null) { return; } 		// TODO:
				onReceive(json);
			}
			}
			break;
		}
	}
		
	
	//
	protected void serviceSend(JSONObject json) {
		Bundle bundle = new Bundle();
		bundle.putInt("what", 0);
		bundle.putString("data", json.toString());
		if(mService == null) { return; }
		try {
			mService.sendMsgToService(bundle);
		} 
		catch (RemoteException e) {
			// e.printStackTrace();
		}
	}
	
	
	protected void serviceSend(JSONArray jarr) {
		Bundle bundle = new Bundle();
		bundle.putInt("what", 0);
		bundle.putString("data", jarr.toString());
		if(mService == null) { return; }
		try {
			mService.sendMsgToService(bundle);
		}
		catch (RemoteException e) {
			// e.printStackTrace();
		}
	}
	
	
	// ----------------------------------------------------------------------------
	private ServiceConnection mConnection = new ServiceConnection() {
		
		public void onServiceConnected(ComponentName className, IBinder service) {

			mService = IRemoteService.Stub.asInterface(service);
			mIsBound = true;
			 try {
				
				Bundle data = new Bundle();
				data.putInt("what", 100);			// init message to remote service
				data.putInt("code_ver", getResources().getInteger(R.integer._PROGRAM_VERSION));
				data.putString("app_name", getString(R.string.app_name));
				data.putString("version", getString(R.string.app_version));
				mService.sendMsgToService(data);
			}
			catch (RemoteException e1) {
				//
			}
			
			try {
				mService.registerCallback(mCallback);
			} 
			catch (RemoteException e) {
				// In this case the service has crashed before we could even
				// do anything with it; we can count on soon being
				// disconnected (and then reconnected if it can be restarted)
				// so there is no need to do anything here.
			}
			
			onServiceConnectionStatus(true);
		}

		
		public void onServiceDisconnected(ComponentName className) {
			mService = null;
			mIsBound = false;
			try {
				mService.unregisterCallback(mCallback);
			} 
			catch (RemoteException e) {
				// e.printStackTrace();
			}
			
			onServiceConnectionStatus(false);
		}
	};

	// ----------------------------------------------------------------------
	// Code showing how to deal with callbacks.
	// ----------------------------------------------------------------------

	private IRemoteServiceCallback mCallback = new IRemoteServiceCallback.Stub() {
		public void sendToClient(Bundle data) {
			Message msg = new Message();
			msg.setData(data);
			mHandler.sendMessage(msg);
		}
	};


	private Handler mHandler = new Handler() {
		@Override
		public void handleMessage(Message msg) {
			Bundle bundle = msg.getData();
			if(bundle != null) { // broadcasted events from remote service
				onMessageReceived(bundle);
			}
			else { 
				super.handleMessage(msg);
			}
		}
	};

	
	// ------------------------------------------------------------------------------------
	
	// protected Profile getApp() { return (Profile)getApplication(); }
	
	// -- protected utility methods ----------------------------
	
	protected void callActivity(Class<?> cls) {
		Intent intent = new Intent(this, cls);
    	intent.setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION | Intent.FLAG_ACTIVITY_NEW_TASK);
    	intent.setAction(Intent.ACTION_MAIN);
    	try { 
    		this.startActivity(intent); 
    	}
    	catch(Throwable ex) {
    		// ex.printStackTrace();
    		Toast.makeText(this, "Start Activity Error: " + ex.getMessage(), Toast.LENGTH_LONG).show();
    	}
	}
	
	
	// --- 
	protected void callActivity(String activityName, String packageName, Bundle bundle) {
		// -- 
		Intent intent = new Intent(Intent.ACTION_MAIN);
        intent.setComponent(new ComponentName(packageName, activityName));
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP);
        intent.setAction(Intent.ACTION_MAIN);
		// --
    	try { 
    		this.startActivity(intent); 
    	}
    	catch(Throwable ex) {
    		// ex.printStackTrace(); 
    		Toast.makeText(this, "Start Activity Error: " + ex.getMessage(), Toast.LENGTH_LONG).show();
    	}
	}
	
	
	// -- ------------------------------------------------------
	
	protected JSONObject toJSON(Bundle bundle) {
		if(bundle == null) { return null; }
		String key;
		JSONObject json = new JSONObject();
		Set<String> keySet = bundle.keySet();
		Iterator<String> it = keySet.iterator();
		while(it.hasNext()) {
			key = it.next();
			try {
				json.put(key, bundle.get(key));
			} 
			catch (JSONException e) {
				// e.printStackTrace();
			}
		}
		return json;
	}
	
	
	// ----------------------------------------------------------------------------
	
}
